<?php
/**
 * User: hjd-yao
 * Date: 2019/1/24
 * Time: 15:01
 */

namespace App\Helpers\Uploader;


use Illuminate\Support\Facades\Storage;
use Stevenyangecho\UEditor\Uploader\UploadFile;
use Illuminate\Http\Request;

class UploadImage extends UploadFile
{
    public $fileMd5;
    public $fileSha1;
    public $fileId;
    public function __construct(array $config, $request)
    {
        parent::__construct($config, $request);
        $this->stateMap['ERROR_MIME_TYPE'] = '图片不合法';
        $this->stateMap['IMG_IS_DANGER'] = '图片存在风险';
        $this->stateMap['IMG_EXIST'] = 'IMG_EXIST';
    }

    public function doUpload()
    {
        $file = $this->request->file($this->fileField);
        if (empty($file)) {
            $this->stateInfo = $this->getStateInfo("ERROR_FILE_NOT_FOUND");
            return false;
        }
        if (!$file->isValid()) {
            $this->stateInfo = $this->getStateInfo($file->getError());
            return false;
        }

        $this->file = $file;

        $this->oriName = $this->file->getClientOriginalName();

        $this->fileSize = $this->file->getSize();
        $this->fileType = $this->getFileExt();

        $this->fullName = $this->fileId = $this->getFullName();


        $this->filePath = $this->getFilePath();

        $this->fileName = basename($this->filePath);

        $this->fileMd5 = md5_file($this->file->getPathname());

        $this->fileSha1 = sha1_file($this->file->getPathname());

        //检查文件大小是否超出限制
        if (!$this->checkSize()) {
            $this->stateInfo = $this->getStateInfo("ERROR_SIZE_EXCEED");
            return false;
        }
        //检查是否不允许的文件格式
        if (!$this->checkType()) {
            $this->stateInfo = $this->getStateInfo("ERROR_TYPE_NOT_ALLOWED");
            return false;
        }

        if(!$this->checkMime()){
            $this->stateInfo = $this->getStateInfo('ERROR_MIME_TYPE');
            return false;
        }

        if(!$this->checkHex()){
            $this->stateInfo = $this->getStateInfo('IMG_IS_DANGER');
            return false;
        }

        if($this->checkHas()){
            $this->stateInfo = $this->getStateInfo('IMG_EXIST');
            return true;
        }

        if(config('UEditorUpload.core.mode')=='local'){
            try {
                $this->file->move(dirname($this->filePath), $this->fileName);

                $this->stateInfo = $this->stateMap[0];

            } catch (FileException $exception) {
                $this->stateInfo = $this->getStateInfo("ERROR_WRITE_CONTENT");
                return false;
            }

        }else if(config('UEditorUpload.core.mode')=='qiniu'){

            $content=file_get_contents($this->file->getPathname());
            return $this->uploadQiniu($this->filePath,$content);

        }else{
            $this->stateInfo = $this->getStateInfo("ERROR_UNKNOWN_MODE");
            return false;
        }
        return true;
    }

    protected function checkMime()
    {
        if(!isset($this->config['mimeType'])){
            return true;
        }
        $mineType = $this->config['mimeType'][$this->fileType];
        return in_array($this->getFileMime(), $mineType);
    }

    protected  function checkHex() {
        $file = $this->file;
        if (file_exists($file)) {
            $resource = fopen($file, 'rb');
            $fileSize = filesize($file);
            fseek($resource, 0); //把文件指针移到头部
            if ($fileSize > 512) { // 若文件大于521B文件取头和尾
                $hexCode = bin2hex(fread($resource, 512));
                fseek($resource, $fileSize - 512); //把文件指针移到文件尾部
                $hexCode .= bin2hex(fread($resource, 512));
            } else { // 取全部
                $hexCode = bin2hex(fread($resource, $fileSize));
            }
            fclose($resource);
            /* 匹配16进制中的 <% ( ) %> */
            /* 匹配16进制中的 <? ( ) ?> */
            /* 匹配16进制中的 <script | /script> 大小写亦可
            /*核心  整个类检测木马脚本的核心在这里  通过匹配十六进制代码检测是否存在木马脚本*/
            $pattern = "/(3c25.*?28.*?29.*?253e)|(3c3f.*?28.*?29.*?3f3e)|(3C534352495054)|(2F5343524950543E)|(3C736372697074)|(2F7363726970743E)/is";
            if (preg_match($pattern, $hexCode)){
                // unlink($this->getFilePath());
                return false;
            }
            return true;
        } else {
            return false;
        }
    }

    public function checkHas()
    {
        if (isset($this->config['callback'])){
            $data = call_user_func($this->config['callback'], ['md5'=>$this->fileMd5,'sha1'=>$this->fileSha1]);
            if($data){
                $this->fullName = $data->path;
                $this->fileId = $data->id;
                return true;
            }
            return false;
        }
        return false;
    }

    /**
     * 重命名文件
     * @return string
     */
    protected function getFullName()
    {
        //替换日期事件
        $t = time();
        $d = explode('-', date("Y-y-m-d-H-i-s"));
        $format = $this->config["pathFormat"];
        $format = str_replace("{group}",$this->config["imageGroup"]??'image',$format);
        $format = str_replace("{yyyy}", $d[0], $format);
        $format = str_replace("{yy}", $d[1], $format);
        $format = str_replace("{mm}", $d[2], $format);
        $format = str_replace("{dd}", $d[3], $format);
        $format = str_replace("{hh}", $d[4], $format);
        $format = str_replace("{ii}", $d[5], $format);
        $format = str_replace("{ss}", $d[6], $format);
        $format = str_replace("{time}", $t, $format);

        //过滤文件名的非法自负,并替换文件名
        $oriName = substr($this->oriName, 0, strrpos($this->oriName, '.'));
        $oriName = preg_replace("/[\|\?\"\<\>\/\*\\\\]+/", '', $oriName);
        $format = str_replace("{filename}", $oriName, $format);

        //替换随机字符串  数值太大可能导致部分环境报错
        $randNum = rand(1, 10000000) . rand(1, 10000000);
        if (preg_match("/\{rand\:([\d]*)\}/i", $format, $matches)) {
            $format = preg_replace("/\{rand\:[\d]*\}/i", substr($randNum, 0, $matches[1]), $format);
        }

        $ext = $this->getFileExt();
        return $format . $ext;
    }

    public function getFileInfo()
    {
        if($this->stateInfo == 'SUCCESS'||$this->stateInfo == 'IMG_EXIST'){
            return [
                'status'=>1,
                'state'=>$this->stateInfo,
                "msg" => $this->stateInfo,
                "url" => $this->fullName,
                "md5" => $this->fileMd5,
                "sha1" => $this->fileSha1,
                "id" => $this->fileId,
            ];
        }else{
            return [
                'status'=>0,
                'state'=>$this->stateInfo,
                "msg" => $this->stateInfo,
            ];
        }

    }


    public function uploadBase64(Request $request)
    {
        $field = $request->post('imgField');
        $imgBase64 = $request->post($field);
        $group = $request->post('group');

        if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $imgBase64, $res)) {
            //获取图片类型
            $type = $res[2];
            if(!in_array('.'.$type, $this->config["allowFiles"])){
                return [
                    'status'=>0,
                    "msg" =>'上传图片格式不正确'
                ];
            }
            //图片名字
            $fileName = md5(time()) . '.' . $type;

            //阿里云oss上传的文件目录
            $dst = $group.'/'.$fileName;
            try{
                $res = Storage::disk('upload')->put($dst,  base64_decode(str_replace($res[1], '', $imgBase64)));
                if($res){
                    $url = Storage::disk('upload')->url($dst);
                    return [
                        'status'=>1,
                        "url" => $url
                    ];
                }

            }catch(FileException $e) {
                return [
                    'status'=>0,
                    "msg" => $e->getMessage()
                ];
            }
        }
        return [
            'status'=>0,
            "msg" =>'图片上传失败'
        ];
    }


}